package edu.ccut.saturn.web;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletRequestContext;

import edu.ccut.saturn.component.ActionViewException;
import edu.ccut.saturn.component.ILogicContext;
import edu.ccut.saturn.component.IView;
import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.component.SaturnValidateFailedException;
import edu.ccut.saturn.component.impl.SaturnLogicContext;
import edu.ccut.saturn.component.impl.node.ActionNodeInfo;
import edu.ccut.saturn.component.utils.ExceptionUtils;
import edu.ccut.saturn.component.utils.MathUtil;
import edu.ccut.saturn.component.view.JspView;
import edu.ccut.saturn.core.IConstants;
import edu.ccut.saturn.core.impl.SaturnPropertiesService;

/**
 * 
 * @author LeslieGu
 * 
 */
public class WebHelper {

	private static final String CODE_ENCODING = "UTF-8";

	private static final String ERROR_JSP = "/error.jsp";

	private static final String ERROR_MESSAGE = "__ERROR_MESSAGE__";

	private HttpServletRequest request;

	private HttpServletResponse response;

	private HttpSession session;

	public WebHelper(HttpServletRequest request, HttpServletResponse response) {
		this.request = request;
		this.response = response;
		this.session = request.getSession();

		this.requestParameter2Attribute(request);
	}

	public HttpServletRequest getRequest() {
		return request;
	}

	public HttpServletResponse getResponse() {
		return response;
	}

	public HttpSession getSession() {
		return session;
	}

	/**
	 * TODO 一个简单的版本实现
	 * 
	 * @return
	 */
	public IView execute() throws Exception {
		// IParameterContext parameterContext = null;
		try {
			String content_type = request.getHeader("content-type");

			if (content_type != null) {

				if (content_type.startsWith("multipart/form-data")
						|| content_type.startsWith("multipart/mixed")) {

					doFile2();
				}
			}
			String componentFullKey = this.getActionKey(this.getRequest()
					.getRequestURI());

			if (componentFullKey.endsWith(".do")) {
				int index = componentFullKey.indexOf("/");
				int length = componentFullKey.length();
				componentFullKey = componentFullKey.substring(0, index) + "::"
						+ componentFullKey.substring(index, length - 3)
						+ ".action";
			}

			ILogicContext logicContext = new SaturnLogicContext(componentFullKey + MathUtil.radom());
			
			new ActionNodeInfo(request, response, componentFullKey)
					.execute(logicContext);

			// IComponent action = ComponentManager.getInstance().getComponent(
			// componentFullKey);
			//
			// parameterContext = ComponentFactory
			// .createParameterContext();
			//
			// parameterContext.addParameter(this.request,
			// HttpServletRequest.class);
			//
			// parameterContext.addParameter(this.response,
			// HttpServletResponse.class);
			//
			// action.execute(parameterContext);

		} catch (ActionViewException e) {
			return e.getView();
		} catch (SaturnComponentException e) {
			request.setAttribute(ERROR_MESSAGE, e.getMessage());
			return new JspView(ERROR_JSP);

		} catch (SaturnValidateFailedException e) {
			request.setAttribute(ERROR_MESSAGE, e.getValidateResult().toXml());
			showValidateErrorInfo(this.response, e.getValidateResult().toXml());
			return new JspView(ERROR_JSP);
		} catch (FileUploadException e) {
			request
					.setAttribute(
							ERROR_MESSAGE,
							"\u4e0a\u4f20\u9644\u4ef6\u5927\u5c0f\u8d85\u8fc7\u7cfb\u7edf\u5141\u8bb8\u8303\u56f4\uff01");
			return new JspView(ERROR_JSP);
		} catch (Exception e) {
		//	e.printStackTrace();
			request.setAttribute(ERROR_MESSAGE, e.getMessage());
			return new JspView(ERROR_JSP);
		}

		return new JspView(ERROR_JSP);
	}

	public void showValidateErrorInfo(HttpServletResponse response, String xml) {
		if (xml != null) {
			PrintWriter out = null;
			try {
				response.setContentType("text/xml; charset=UTF-8");
				out = response.getWriter();
				out.write(xml);
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				out.flush();
			}
		}
	}

	/**
	 * 转file文件转为byte[]上传一个包含一个附件的文件域，数据项可直接拼装
	 * 
	 * @author yanshuang
	 * @throws FileUploadException
	 */
	@SuppressWarnings("unchecked")
	public void doFile() throws Exception {
		DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
		FileUpload fileUpload = new FileUpload();
		// 设置允许用户上传文件大小,单位:字节
		fileUpload.setSizeMax(2000000);// 2M
		// 设置最多只允许在内存中存储的数据,单位:字节
		fileItemFactory.setSizeThreshold(2 * 1024 * 1024);

		// 设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录
		// fileItemFactory.setRepository(new File("D:\\upload\\tmp"));
fileUpload.setFileItemFactory(fileItemFactory);

		RequestContext requestContext = new ServletRequestContext(request);
		// 开始读取上传信息
		List<Object> fileItems = fileUpload.parseRequest(requestContext);
		Iterator<Object> iter = fileItems.iterator();

		while (iter.hasNext()) {
			FileItem item = (FileItem) iter.next();
			// 其他不是文件域的所有表单信息,设置回去，否则取不到
			Object attributeValue = null;
			if (item.isFormField()) {
				attributeValue = request.getAttribute(item.getFieldName());
				if (attributeValue != null) {
					// list
					if (attributeValue instanceof List) {
						((List) attributeValue).add(item
								.getString(CODE_ENCODING));

						request.setAttribute(item.getFieldName(),
								attributeValue);
					} else {
						// String
						List<String> tempList = new ArrayList<String>();
						tempList.add((String) attributeValue);
						tempList.add(item.getString("UTF-8"));
						request.setAttribute(item.getFieldName(), tempList);
					}
				} else {
					request.setAttribute(item.getFieldName(), item
							.getString(CODE_ENCODING));
				}
			} else {
				// 文件域
				InputStream is = null;

				try {
					// 按流传不能关闭流
					is = item.getInputStream();
					byte[] value = new byte[is.available()];
					is.read(value);
					request.setAttribute(item.getFieldName(), value);
					String name = item.getName();
					if (name.contains("\\")) {
						name = name.substring(name.lastIndexOf("\\") + 1, name
								.length());
					}
					request.setAttribute(item.getFieldName() + "_fileName",
							name);
				} catch (Exception e) {
					throw e;

				} finally {
					if (is != null) {
						is.close();
					}
				}

			}
		}
	}

	/**
	 * 转file文件转为byte[] 上传一个包含多个附件的文件域
	 * 
	 * @author yanshuang
	 * @throws FileUploadException
	 * @throws IOException
	 * @throws
	 */
	@SuppressWarnings("unchecked")
	public void doFile2() throws Exception {
		DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
		FileUpload fu = new FileUpload();
		// 设置允许用户上传文件大小,单位:字节
		fu.setSizeMax(2000000);// 2M
		// 设置最多只允许在内存中存储的数据,单位:字节
		fileItemFactory.setSizeThreshold(2 * 1024 * 1024);
		// 设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录
		// fileItemFactory.setRepository(new File("D:\\upload\\tmp"));
fu.setFileItemFactory(fileItemFactory);
		RequestContext requestContext = new ServletRequestContext(request);
		// 开始读取上传信息
		List<Object> fileItems = fu.parseRequest(requestContext);
		Iterator<Object> iter = fileItems.iterator();
		// 将文件存储成文件list
		while (iter.hasNext()) {
			FileItem item = (FileItem) iter.next();
			// 其他不是文件域的所有表单信息,设置回去，否则取不到
			if (item.isFormField()) {
				request.setAttribute(item.getFieldName(), item
						.getString(CODE_ENCODING));

			} else {
				// 文件域
				InputStream is = null;
				try {
					ArrayList<HashMap<String, Object>> filesList = null;
					String filename = item.getFieldName();
					if (request.getAttribute(filename) == null) {
						filesList = new ArrayList<HashMap<String, Object>>();
						request.setAttribute(filename, filesList);
					} else {
						filesList = (ArrayList<HashMap<String, Object>>) request
								.getAttribute(filename);
					}
					HashMap<String, Object> fileMap = new HashMap<String, Object>();

					is = item.getInputStream();
					byte[] value = new byte[is.available()];
					is.read(value);
					fileMap.put("content", value);
					String name = item.getName();
					if (name.contains(File.separator)) {
						name = name.substring(
								name.lastIndexOf(File.separator) + 1, name
										.length());
					}
					fileMap.put("name", name);
					fileMap.put("size", item.getSize());
					filesList.add(fileMap);
				} catch (Exception e) {
					throw e;

				} finally {
					is.close();
				}
			}
		}
	}

/*	private String getActionKey(String requestURI) {
		return requestURI.substring(requestURI.indexOf("/", 1) + 1);
	}*/
	//emily:解决jboss下不能直接访问action的问题
	private String getActionKey(String requestURI) {
		String context_name = requestURI.substring(requestURI.indexOf("/", 0) + 1, requestURI.indexOf("/", 2));

		String serverLocation  =  SaturnPropertiesService.getInstance().getProperty(IConstants.SATURN_SERVER_LOCATION);
//		int p = a.lastIndexOf("\\");
		String serverName = serverLocation.substring(serverLocation.lastIndexOf("\\")+1);
		if(serverName.equals(context_name)){
			return requestURI.substring(requestURI.indexOf("/", 1) + 1);
		}else{
			return requestURI.substring(requestURI.indexOf("/", 0) + 1);
		}
		
		//return requestURI.substring(requestURI.indexOf("/", 1) + 1);
	}

	@SuppressWarnings("unchecked")
	private void requestParameter2Attribute(HttpServletRequest request) {
		Map<String, Object> parameters = request.getParameterMap();

		for (String key : parameters.keySet()) {
			String[] values = request.getParameterValues(key);

			if (values != null) {
				if (values.length == 1) {
					request.setAttribute(key, values[0]);
				}

				if (values.length > 1) {
					String totalValue = "";
					for (int i = 0; i < values.length; ++i) {
						String value = values[i];
						totalValue += value;

						if (i != values.length) {
							totalValue += ",";
						}
					}

					request.setAttribute(key, totalValue);
				}
			}
		}
	}
}
